package com.scs.application.modules.wm.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.modules.base.service.WarehouseService;
import com.scs.application.modules.dept.entity.OprtApply;
import com.scs.application.modules.dept.entity.OprtApplyItem;
import com.scs.application.modules.dept.service.OprtApplyItemService;
import com.scs.application.modules.dept.service.OprtApplyService;
import com.scs.application.modules.wm.dto.OprtPrepareDTO;
import com.scs.application.modules.wm.entity.OprtPrepare;
import com.scs.application.modules.wm.entity.OprtPrepareItem;
import com.scs.application.modules.wm.entity.Stock;
import com.scs.application.modules.wm.entity.StockLock;
import com.scs.application.modules.wm.enums.LockBusType;
import com.scs.application.modules.wm.enums.UniqueCodeType;
import com.scs.application.modules.wm.mapper.OprtPrepareItemMapper;
import com.scs.application.modules.wm.service.OprtPrepareItemService;
import com.scs.application.modules.wm.service.OprtPrepareService;
import com.scs.application.modules.wm.service.StockLockService;
import com.scs.application.modules.wm.service.StockService;
import com.scs.application.modules.wm.utils.UniqueCodeUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Service
public class OprtPrepareItemServiceImpl extends BaseServiceImpl<OprtPrepareItemMapper, OprtPrepareItem> implements OprtPrepareItemService {
    @Autowired
    private StockService stockService;

    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    private StockLockService stockLockService;

    @Autowired
    private OprtApplyService oprtApplyService;

    @Autowired
    private OprtApplyItemService oprtApplyItemService;

    @Autowired
    private OprtPrepareService oprtPrepareService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPrepareItem(String prepareId, String uniqueCode, String warehouseId) {
        Stock stock = check(prepareId, uniqueCode, warehouseId);
        String packPrepareItemId = addOprtPrepareItemAndLock(stock, prepareId, uniqueCode, warehouseId);
        List<Stock> stocks = stockService.list(Wrappers.<Stock>query().eq("pack_stock_id", stock.id));
        stocks.stream().forEach(item -> {
            addOprtPrepareItemAndLockMatr(item, prepareId, warehouseId, packPrepareItemId);
        });
    }

    @Override
    public void addByOprtApply(Map<String, Serializable> map) {
        OprtApply apply = oprtApplyService.getById(map.get("oprtApplyId"));
        List<OprtApplyItem> oprtApplyItems = oprtApplyItemService.list(new QueryWrapper<OprtApplyItem>().select()
                .eq("oprt_apply_id", apply.getId())
                .eq("status", 0)
                .eq("matr_type", "1"));
        OprtPrepareItem oprtPrepareItem = new OprtPrepareItem();
        oprtApplyItems.stream().forEach(s -> {
            BeanUtils.copyProperties(s, oprtPrepareItem);
//            oprtPrepareItem.setStockId(s.getId());
            oprtPrepareItem.setLineId("-1");
            oprtPrepareItem.setLot("");
            oprtPrepareItem.setAmount(s.getSkuPrice());
            oprtPrepareItem.setId(null);
            oprtPrepareItem.setPrepareId(map.get("id").toString());
            super.save(oprtPrepareItem);
        });


    }

    @Override
    public void deletePackage(Serializable id) {
        OprtPrepareItem prepareItem = this.getById(id);
        OprtPrepare oprtPrepare = oprtPrepareService.getById(prepareItem.getPrepareId());
        if (prepareItem.getStockId() == null) {
            throw new BusinessException(String.format("库存中未找到id为%s跟台包", id));
        }
        List<OprtPrepareItem> prepareItems = this.list(new QueryWrapper<OprtPrepareItem>().select("id", "stock_id").eq("pack_prepare_item_id", id));
        if (prepareItems.isEmpty()) {
            this.removeById(id);
            stockLockService.unlock(prepareItem.getStockId());
        } else {
            List<String> ids = prepareItems.stream().map(s -> s.getId()).collect(Collectors.toList());
            this.removeByIds(ids);
            this.removeById(id);
            stockLockService.unlock(prepareItem.getSn(), UniqueCodeType.SN, oprtPrepare.getWarehouseId());
            prepareItems.stream().forEach(s -> stockLockService.unlock(s.getStockId()));
        }

    }

    @Override
    public void deleteMatr(Serializable id) {
        OprtPrepareItem prepareItem = this.getById(id);
        if (prepareItem == null) {
            throw new BusinessException(String.format("很抱歉！ 在跟台包中未找到id为%s相关的耗材", id));
        }
        boolean success = this.removeById(id);
        if (success) {
            updatePrepareItemAmount(prepareItem);
            stockLockService.unlock(prepareItem.getStockId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBatch(List<OprtPrepareItem> itemList) {
        List<String> stockIdList = itemList.stream().map(OprtPrepareItem::getStockId).collect(Collectors.toList());
        List<StockLock> stockLockList = stockLockService.list(Wrappers.<StockLock>query().in("stock_id",stockIdList));
        if (ObjectUtil.length(stockLockList) > 0) {
            BusinessException.throwError("标签【】已被锁定,请勿重复操作",stockLockList.get(0).getUc());
        }
        List<Stock> stockList = stockService.list(Wrappers.<Stock>query().in("id",stockIdList));
        if (ObjectUtil.length(stockList) != ObjectUtil.length(itemList)) {
            BusinessException.throwError("库存状态发生变化，请重新选择",stockLockList.get(0).getUc());
        }

        OprtPrepare oprtPrepare = oprtPrepareService.getById(itemList.get(0).getPrepareId());
        BusinessException.throwErrorIf(oprtPrepare == null,"备货单已被删除，请刷新界面");
        BusinessException.throwErrorIf(!GlobalConsts.FLOW_START_VALUE.equals(oprtPrepare.getFlowStatus()),"备货单当前状态不可操作，请刷新界面");

        // 包内明细库存
        List<Stock> stockDtlList = stockService.list(Wrappers.<Stock>query().in("pack_stock_id", stockIdList).isNotNull("pack_stock_id"));

        // 包
        List<OprtPrepareItem> prepareItemListSave = new ArrayList<>();
        BeanUtils.copyProperties(stockList, prepareItemListSave, "id");
        stockList.forEach(stockPack -> {
            OprtPrepareItem itemPack = new OprtPrepareItem();
            BeanUtils.copyProperties(stockPack, itemPack, "id");
            itemPack.setPrepareId(oprtPrepare.getId());
            itemPack.setStockId(stockPack.getId());
            itemPack.setPackId(itemPack.getStockId());
            itemPack.setId(IdWorker.getIdStr());
            prepareItemListSave.add(itemPack);
            stockDtlList.stream().filter(tmp -> tmp.getPackStockId().equals(stockPack.getId())).forEach(stockDtl -> {
                       OprtPrepareItem itemDtl = new OprtPrepareItem();
                       BeanUtils.copyProperties(stockDtl, itemDtl, "id");
                       itemDtl.setPrepareId(oprtPrepare.getId()).setPackPrepareItemId(itemPack.getId());
                       itemDtl.setStockId(stockDtl.getId());
                        prepareItemListSave.add(itemDtl);
               });
            }
        );

        this.saveBatch(prepareItemListSave);

        // 批量锁定
        stockLockService.lockBatch(
                LockBusType.OPRT_PREPARE, oprtPrepare.getPrepareKey(), oprtPrepare.getWarehouseId(), "跟台备货锁",
                prepareItemListSave.stream().map(OprtPrepareItem::getSn).collect(Collectors.toList()), oprtPrepare.getPrepareKey()
        );
    }

    @Override
    public void addScan(OprtPrepareDTO item) {
        Stock stock = stockService.getStockByUniqueCode(item.getUniqueCode());
        BusinessException.throwErrorIf(stock == null || stock.getSkuQty() == 0, "标签码不存在");
        BusinessException.throwErrorIf(!stock.getWarehouseId().equals(item.getWarehouseId()), "标签码不在所配送仓库");
        BusinessException.throwErrorIf(!"1".equals(stock.getMatrType()), "标签码不是包库存，不支持扫描");
        OprtPrepareItem prepareItem = new OprtPrepareItem();
        prepareItem.setPrepareId(item.getPrepareId()).setStockId(stock.getId());
        addBatch(Arrays.asList(prepareItem));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        List<OprtPrepareItem> packList = (List<OprtPrepareItem>) this.listByIds(idList);
        if (packList.isEmpty()) {
            return  true;
        }
        List<String> snList = packList.stream().map(OprtPrepareItem::getSn).collect(Collectors.toList());

        super.removeCascadeByIds(idList);

        // 对应的包明细
        List<OprtPrepareItem> packItemList =this.list(Wrappers.<OprtPrepareItem>query().in("pack_prepare_item_id",idList).isNotNull("pack_prepare_item_id"));
        if (!packItemList.isEmpty()) {
            snList.addAll(packItemList.stream().map(OprtPrepareItem::getSn).collect(Collectors.toList()));
            super.removeByIds(packItemList.stream().map(OprtPrepareItem::getId).collect(Collectors.toList()));
        }
        stockLockService.unlockBatch(snList);
        return true;
    }

    private void updatePrepareItemAmount(OprtPrepareItem prepareItem) {
        Map<String, Object> map = this.getMap(new QueryWrapper<OprtPrepareItem>().select("sum(amount) as amount")
                .eq("pack_prepare_item_id", prepareItem.getPackPrepareItemId()));
        this.update(Wrappers.<OprtPrepareItem>update()
                .set("amount", map.get("amount") == null ? 0 : map.get("amount"))
                .eq("id", prepareItem.getPackPrepareItemId()));
    }

    public Stock check(String prepareId, String uniqueCode, String warehouseId) {
        Stock stock = stockService.getStockByUniqueCode(uniqueCode);
        if (stock == null) {
            throw new BusinessException(String.format("很抱歉！ 在库存中未找到%s相关的跟台包", uniqueCode));
        }
        if (super.list(new QueryWrapper<OprtPrepareItem>().eq("prepare_id", prepareId).eq("stock_id", stock.getId())).size() > 0) {
            throw new BusinessException(String.format("很抱歉！ %s相关的耗材已添加至手术备货单", uniqueCode));
        }
        if (!stock.getWarehouseId().equals(warehouseId)) {
            String warehouseName = warehouseService.getById(warehouseId).getName();
            throw new BusinessException(String.format("很抱歉！ %s相关的跟台包不在指定的仓库库存%s中", uniqueCode, warehouseName));
        }
        if (!"1".equals(stock.getMatrType())) {
            throw new BusinessException(String.format("很抱歉！ %s不是跟台包类型,请扫描跟台包SN！", uniqueCode));
        }
        return stock;
    }

    /**
     * 跟台包添加备货明细及锁库
     *
     * @param stock       跟台包库存对象
     * @param prepareId   备货单主表ID
     * @param uniqueCode  唯一码
     * @param warehouseId 仓库ID
     */
    public String addOprtPrepareItemAndLock(Stock stock, String prepareId, String uniqueCode, String warehouseId) {
        OprtPrepareItem oprtPrepareItem = new OprtPrepareItem();
        BeanUtils.copyProperties(stock, oprtPrepareItem);
        oprtPrepareItem.setStockId(stock.getId());
        oprtPrepareItem.setId(null);
        oprtPrepareItem.setPrepareId(prepareId);
        oprtPrepareItem.setMatrType("1");
        super.save(oprtPrepareItem);
        //加锁
        UniqueCodeType uniqueCodeType = UniqueCodeUtils.getUniqueCodeType(uniqueCode);
        stockLockService.lock(LockBusType.OPRT_PREPARE, oprtPrepareItem.getId(), warehouseId, uniqueCode,
                uniqueCodeType, "跟台手术备货单加锁");
        return oprtPrepareItem.getId();

    }

    /**
     * 一物一码添加备货明细及锁库
     *
     * @param stock       耗材库存对象
     * @param prepareId   备货单主表ID
     * @param warehouseId 仓库ID
     */
    public void addOprtPrepareItemAndLockMatr(Stock stock, String prepareId, String warehouseId, String packPrepareItemId) {
        OprtPrepareItem oprtPrepareItem = new OprtPrepareItem();
        BeanUtils.copyProperties(stock, oprtPrepareItem);
        oprtPrepareItem.setStockId(stock.getId());
        oprtPrepareItem.setId(null);
        oprtPrepareItem.setPrepareId(prepareId);
        oprtPrepareItem.setPackPrepareItemId(packPrepareItemId);
        super.save(oprtPrepareItem);
        //加锁
        UniqueCodeType uniqueCodeType = UniqueCodeUtils.getUniqueCodeType(stock.getSn());
        stockLockService.lock(LockBusType.OPRT_PREPARE, oprtPrepareItem.getId(), warehouseId, stock.getSn(),
                uniqueCodeType, "跟台手术备货单加锁");
    }
}
